<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel='stylesheet' href='../rurple.css' type='text/css'>
<title>神奇-第五部分</title>
</head>
<body>
<h2 class="title">21. 神奇-第五部分</h2>
<h3 class="section">更复杂的情况</h3>
<p>假设以下场景</p>
<p><img alt="around the world: start" src=
"../../images/intro/around4start.png"></p>
<p>之前编写的程序能够解决这个问题吗？试试看吧！</p>
<p>正如你可能猜到的那样，如果你不去试试 <small>(你应该去试试，真的！)</small>, 它不能解决这个问题。 
为了使它能够解决这个问题，我们需要替换之前加在<span class=
"pykeyword">while</span>后的<span class="pykeyword">if</span>。去试试吧！记得要保存它。</p>
<!--=====================================-->
<hr width="50%">
<h3 class="section">明确我们的目的</h3>
<p>我们似乎设计了一个可以应对有可能遇到的所有情况的程序。如果我们没有忘记，这个程序是为了使我们的小机器人“Reeborg”能够探索他的世界，走完一遍。虽然这个程序很短，结构也很清晰，但对于哪些凑巧第一次遇到的人而言也许还不是这么显而易见。给它加上一些注释并（或者）采用一些带有含义的词也许是个不错的主意。让我们就从加注释开始吧！不过它允许会比想象中的要冗长。</p>
<pre>
<span class="comment"># 我们定义一个有用的命令</span>
<span class="keyword">def</span> turn_right():
    repeat(turn_left, 3)

<span class=
"comment"># 我们放下一个beeper来标记起点</span>
put_beeper()

<span class=
"comment"># 然后我们找到一个明确的方向，开始运动。</span>
<span class="keyword">while not</span> front_is_clear():
    turn_left()
move()

<span class="comment"># 当我们回到我们之前放下的beeper的时候，</span>
<span class="comment"># 我们知道已经在这个世界中走过了一遍</span>

<span class="keyword">while not</span> on_beeper():
    <span class="keyword">if</span> right_is_clear(): <span class=
"comment">顺着墙一直左转</span>
        turn_right()
        move()
    <span class="keyword">elif</span> front_is_clear(): <span class=
"comment"># 沿着右边的墙走</span>
        move()
    <span class="keyword">else</span>:<span class=
"comment"> # 沿着墙并左转</span>
        turn_left()

turn_off()
</pre>
<p>虽然这些注释使我们清楚了每个指令的目的，但对我们在总结解决这种问题的方法（也被称为<i>算法</i>）的时候并没有多大帮助。因此，这些注释对其他读者并不会如我们期望的那样有帮助。阅读这些注释，我们注意到这个程序包括两个部分： 
<br>
1) 标记起点；<br>
2) 沿着右边的墙走，直到回到起点。<br>
为了让这两个部分更加清晰，我们现在重新编写这个程序并换种方式写备注。</p>
<pre>
<span class=
"comment"># 这个程序命令Reeborg逆时针绕地图一周</span>
<span class="comment"># 并在原起点停止。 </span>

<span class="keyword">def</span> turn_right():
    repeat(turn_left, 3)

<span class="keyword">def</span> mark_starting_point_and_move():
    put_beeper()
    <span class="keyword">while not</span> front_is_clear():
        turn_left()
    move()

<span class="keyword">def</span> follow_right_wall():
    <span class="keyword">if</span> right_is_clear(): 
        turn_right()
        move()
    <span class="keyword">elif</span> front_is_clear(): 
        move()
    <span class="keyword">else</span>: 
        turn_left()

found_starting_point = next_to_a_beeper   <span class=
"comment"># beeper标记起点</span>

<span class="comment">#=== 定义结束，下面开始solution</span>

mark_starting_point_and_move()
            
<span class="keyword">while not</span> found_starting_point(): 
    follow_right_wall()
      
turn_off()
</pre>
<p>是不是变得更清楚了呢？现在假设开始的时候每一个转角都有一个beeper，然后我们可以选择通过<i>移动</i>beeper来标记起点。我们需要改写一些定义，但大部分的solution可以不变。</p>
<!--======================================-->
<hr width="50%">
<h3 class="try">惊喜一</h3>
<p>修改你刚才写下的程序来去掉<tt>put_beeper()</tt>指令。保存之后，利用这个稍微改造过的程序来完成下面这个跨栏游戏。（文件：hurdles3.wld）</p>
<p><img alt="hurdles" src="../../images/intro/hurdles3_start.png"></p>
<p>神奇吧！我们刚编写的程序可以解决这个跨栏难题，而没有在完成之后转向了另外一个方向（也许是成功之后向观众鞠躬致意）。这个程序在高低不一的栏架上也适用（文件：hurdles4.wld）。如下图所示，我们先前设计的程序是不可能解决这个难题的！</p>
<p><img alt="hurdles" src="../../images/intro/hurdles4_start.png"></p>
<!--======================================-->
<hr width="50%">
<h3 class="try">Amazing surprise</h3>
<p>再用这个程序来解决一下在我们第一课中介绍的迷宫问题，如下图所示。</p>
<p><img alt="maze" src="../../images/intro/maze1_start.png"></p>
<p>正如你将要看到的一样，我们简简单单的程序可以找到迷宫的出口！神奇吧！</p>
<!--======================================-->
<hr width="50%">
<h3 class="section">Conclusion</h3>
<p>我们从解决一个简单的问题开始（环游一个矩形的世界），一点一点（也称作逐步精化），我们成功设计了一个可以解决貌似不相关的其他问题。在每一步，我们保持较小的修改，并且保证我们在考虑更复杂的方案之前，已经有一个行之有效的解决方案。同时，在部分<i>算法</i> 中，我们也使用了更具有描述性的名称，来使得程序更容易读，而且有可能更容易懂。</p>
<dl>
<dt><b>规则 # 5</b></dt>
<dd>编写一个程序应该遵循如下步骤：</dd>
<ul>
<li>用最简单的方法开始；</li>
<li>引入一些小改动，一次一点；</li>
<li>确保每次引入的改动不会破坏已有的程序；</li>
<li>作为补充，加入恰当的注释，但不要重复程序的意图；</li>
<li>并且为定义选择有意义的名字。</li>
</dl>
</ul>
<center><a href="20-amazing4.htm"><img alt="previous" src=
"../../images/previous.png"> 神奇-第四部分</a> - <a href=
"../lessons_toc.htm"><img alt="home" src="../../images/home.png"></a> - <a href=
"22-rain.htm">下雨了！ <img alt="next" src=
"../../images/next.png"></a>
</center>
</body>
</html>
